package com.shiguiwu.springboot3.controller;

import com.shiguiwu.springboot3.annotation.LoginAnnotation;
import com.shiguiwu.springboot3.dto.AuthUser;
import com.shiguiwu.springboot3.dto.request.LoginRequest;
import com.shiguiwu.springboot3.dto.request.RegisterRequest;
import com.shiguiwu.springboot3.dto.response.LoginResponse;
import com.shiguiwu.springboot3.dto.response.RefreshResponse;
import com.shiguiwu.springboot3.service.MemberService;
import com.shiguiwu.springboot3.service.RedisService;
import com.shiguiwu.springboot3.service.TokenBlackService;
import com.shiguiwu.springboot3.service.TokenService;
import com.shiguiwu.springboot3.util.JwtUtils;
import com.shiguiwu.springboot3.util.MemberContextUtils;
import com.shiguiwu.springboot3.util.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseCookie;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.Duration;
import java.util.Map;

@Tag(name = "会员登录认证", description = "会员登录认证操作接口")
@RestController
@RequestMapping("/auth")
public class AuthController {

    @Autowired
    private MemberService memberService;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private RedisService redisService;

    @Autowired
    private TokenBlackService tokenBlackService;

    @Resource
    private AuthenticationManager authenticationManager;


    @Autowired
    private TokenService tokenService;

    @LoginAnnotation
    @Operation(summary = "用户登录", description = "用户登录接口")
    @PostMapping("/login")
    public R<LoginResponse> login(@RequestBody LoginRequest loginRequest, HttpServletResponse response) {

        // 验证用户凭证
        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
        SecurityContextHolder.getContext().setAuthentication(authToken);
        Authentication authenticated = authenticationManager.authenticate(authToken);

        AuthUser authenticate = (AuthUser) authenticated.getPrincipal();
        return R.ok(tokenService.createToken(authenticate));
    }


    @Operation(summary = "用户注册", description = "用户注册接口")
    @PostMapping("/register")
    public R<?> registerUser(@RequestBody @Valid RegisterRequest registerRequest) {

        // 4. 可以选择直接返回成功信息，或者生成Token并返回以简化登录流程[1](@ref)
        return R.ok(Map.of("message", "用户注册成功", "id", memberService.register(registerRequest)));
    }


    @Operation(summary = "刷新token", description = "刷新token接口")
    @PostMapping("/refresh")
    public R<RefreshResponse> refreshToken(@CookieValue("refresh_token") String refreshToken) {

        // 1. 验证Refresh Token是否存在
        if (refreshToken == null || refreshToken.isEmpty()) {
            return R.failed("缺少刷新令牌");
        }

        // 2. 验证Refresh Token的有效性（检查签名和过期时间）
        if (!jwtUtils.validateToken(refreshToken)) {
            return R.failed("刷新令牌无效或已过期");
        }

        // 3. 从Redis中验证此Refresh Token是否有效（是否已被注销）[6](@ref)
        String username = jwtUtils.extractToken(refreshToken);
        String storedToken = redisService.getRefreshToken(username);

        if (storedToken == null || !storedToken.equals(refreshToken)) {
            return R.failed("刷新令牌已失效");
        }

        // 4. 生成新的Access Token（和可选的新的Refresh Token）

        String newAccessToken = tokenService.getToken(MemberContextUtils.getCurrentMember());

        // （可选）生成新的Refresh Token并更新Redis，实现Refresh Token的轮换[6](@ref)
        String newRefreshToken = jwtUtils.generateRefreshToken(username);
        //redisTemplate.opsForValue().set(redisKey, newRefreshToken, jwtUtils.getRefreshExpiration(), TimeUnit.MILLISECONDS);
        redisService.storeRefreshToken(username, newRefreshToken, jwtUtils.getRefreshExpiration());
        // 5. 返回新的Token
        RefreshResponse response = new RefreshResponse(newAccessToken);
        // 如果生成了新的Refresh Token，通常通过Set-Cookie响应头将其设置到客户端
        ResponseCookie refreshTokenCookie = ResponseCookie.from("refresh_token", newRefreshToken)
                .httpOnly(true)
                .secure(true) // 仅HTTPS传输
                .path("/auth/refresh")
                .maxAge(Duration.ofDays(7))
                .sameSite("Strict")
                .build();

        return R.ok(response);
    }

    @Operation(summary = "用户登出", description = "用户登出接口")
    @PostMapping("/logout")
    public R<?> logout(HttpServletRequest request,
                                    HttpServletResponse response,
                                    @CookieValue(value = "refresh_token", required = false) String refreshToken) {

        // 1. 从Authorization头中提取JWT
        String authHeader = request.getHeader("Authorization");
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            return R.failed("Missing or invalid authorization header");
        }
        String accessToken = authHeader.substring(7);

        // 2. 将Access Token加入黑名单（使其立即失效）
        tokenBlackService.addToBlacklist(accessToken);

        // 3. 处理Refresh Token（使其失效）
        if (refreshToken != null) {
            // 方案A: 从存储中直接删除（最彻底）
            redisService.delRefreshToken(refreshToken);
            // 方案B: 也可将其加入黑名单，逻辑同Access Token
            // tokenBlacklistService.addToBlacklist(refreshToken);
            //tokenService.deleteToken(accessToken);
            // 清除客户端的Refresh Token Cookie
            Cookie cookie = new Cookie("refresh_token", null);
            cookie.setHttpOnly(true);
            cookie.setSecure(true);
            cookie.setPath("/auth");
            cookie.setMaxAge(0); // 立即过期
            response.addCookie(cookie);
        }

        // 4. 返回成功响应
        return R.ok(Map.of("code", 200, "message", "Logout successful"));
    }

}